package dirsync

import (
	"fmt"
	"runtime"
	"sync"
	"sync/atomic"
	"time"

	"lukechampine.com/blake3"
)

// 计算文件的哈希值
func calculateFileHash(data []byte) string {
	hash := blake3.Sum256(data)
	return fmt.Sprintf("%x", hash)
}

// 并发抽样校验文件的哈希值
func checkFileHashBySampling(srcData, dstData []byte, fileSize int64) bool {
	sampleCount := 100
	blockSize := int64(1024 * 100) // 100KB 块大小

	// 根据系统CPU核心数确定并发数
	concurrency := runtime.NumCPU()
	if concurrency < 2 {
		concurrency = 2
	} else if concurrency > 8 {
		concurrency = 8 // 设置上限，避免过多并发
	}

	semaphore := make(chan struct{}, concurrency)

	var wg sync.WaitGroup
	done := make(chan struct{})

	// 使用带缓冲的通道，避免阻塞
	resultChan := make(chan bool, sampleCount)

	// 创建一个标志，表示是否已经找到不匹配的块
	var foundMismatch atomic.Bool

	// 启动一个协程等待所有工作完成
	go func() {
		wg.Wait()
		close(done)
		close(resultChan) // 安全关闭结果通道
	}()

	// 启动采样协程
	for i := 0; i < sampleCount; i++ {
		wg.Add(1)
		go func(i int) {
			defer wg.Done()

			// 如果已经找到不匹配，直接返回
			if foundMismatch.Load() {
				return
			}

			semaphore <- struct{}{}
			defer func() { <-semaphore }()

			offset := int64(i) * (fileSize / int64(sampleCount))

			if fileSize <= blockSize {
				// 对于小文件，只取一个样本
				offset = 0
				blockSize = fileSize
			} else if offset+blockSize > fileSize {
				offset = fileSize - blockSize
			}

			srcHash := calculateFileHash(srcData[offset : offset+blockSize])
			dstHash := calculateFileHash(dstData[offset : offset+blockSize])

			if srcHash != dstHash {
				foundMismatch.Store(true)
				resultChan <- false
			} else {
				resultChan <- true
			}
		}(i)
	}

	// 等待所有协程完成或找到不匹配
	select {
	case <-done:
		// 所有协程已完成
	case <-time.After(30 * time.Second):
		// 设置超时，避免无限等待
		return false
	}

	// 检查结果
	for result := range resultChan {
		if !result {
			return false
		}
	}

	return true
}

// 校验文件是否一致
func checkFileConsistency(srcData, dstData []byte, fileSize int64) bool {
	// 如果文件大小为 0，直接返回 true
	if fileSize == 0 {
		return true
	}

	// 对于小文件（<=100MB），计算整个文件的哈希值
	if fileSize <= 100*1024*1024 {
		srcHash := calculateFileHash(srcData)
		dstHash := calculateFileHash(dstData)
		return srcHash == dstHash
	} else {
		// 对于大文件，使用抽样校验
		return checkFileHashBySampling(srcData, dstData, fileSize)
	}
}

// ErrorCallback 定义错误消息回调函数类型
//
// 参数:
//   - srcPath: 源文件路径(删除操作时可能为空)
//   - dstPath: 目标文件路径
//   - err: 发生的错误
type ErrorCallback func(srcPath, dstPath string, err error)

// DeleteCallback 定义删除文件回调函数类型
//
// 参数:
//   - path: 被删除的文件或目录路径
type DeleteCallback func(path string)
